/* Interface.h
Copyright (c) 2008 Michael Zahniser
Please note the license terms (MIT license) at the end of this document.

Header file for the Interface class, which represents a window (possibly full-screen)
containing any number of Views (possibly overlapping) within it.

TODO: How to specify a window centered in the view? Add(view, region, options) where
	options include ALIGN_LEFT, ALIGN_RIGHT, ALIGN_TOP, ALIGN_BOTTOM;
	also DRAGGABLE, ALWAYS_ON_TOP. CLOSABLE? DRAG_BAR??
	That would mean that (x, y) never have to be negative. What about width and height?
*/

#ifndef __MZ_INTERFACE_H__
#define __MZ_INTERFACE_H__

#include "Window.h"

#include "View.h"
#include "Rectangle.h"
#include "EventHandler.h"
#include "_common/Callback.h"

#include <list>

using std::list;



class Interface : private Window {
public:
	typedef CallbackT<const View *> Callback;


public:
	// Initialize the interface with the given command line arguments and the given
	// window dimensions. If the dimensions are zero, the interface is full-screen.
	Interface(int width = 0, int height = 0);
	// Destroy the interface.
	~Interface();
	
	// Allow resizing of the view. Call this _before_ StartSDL() or Run().
	void AllowResizing();
	// Initialize SDL. This must be called before any other SDL functions.
	bool StartSDL();

	// Set the caption of the window.
	using Window::SetCaption;
	// Set the background color of the window.
	void SetBackground(int red, int green, int blue);
	// Toggle drawing of the background.
	void ShowBackground(bool show = true);

	// Add a view to the interface, at the given coordinates.
	// A negative x or y, or a nonpositive width or height, will be added to the
	// window width or height, respectively, e.g. Add(rightBar, -200, 0, 200, 0).
	void Add(View *view, int x = 0, int y = 0, int width = 0, int height = 0);
	void Add(View *view, Rectangle bounds);
	// Add an event handler, with no view associated with it.
	// Its priority in processing events depends on the order in which it was
	// added to the interface. In general, the last view or handler added has
	// the first look at events.
	void AddEventHandler(EventHandler &handler);
	// Mark the given view for deletion. It will be removed before the next time that
	// the interface is redrawn.
	void Remove(View *view);
	// Register the given callback to be called when the given view is removed.
	void OnRemove(const View *view, Callback *callback);
	// Bring the given view to the front.
	void BringToFront(View *view);
	// Hide the given view (and optionally, show the other in its place).
	void Hide(View *view, View *other);
	// Show the given view.
	void Show(View *view);
	// Invalidate the interface (request that it be redrawn).
	void Invalidate();

	// Lock or unlock the view positions. By default, they are locked.
	// If unlocked, you can drag views around by option-clicking.
	void Lock();
	void Unlock();


	// Begin the event loop for the interface. This function blocks until the program
	// quits (through a child view calling Interface::Quit()).
	// If the interface cannot run, this function returns false and an error message
	// is printed to cerr.
	// SDL is not started, and views are not initialized, until Run() is called. Views
	// will be initialized in the order in which they were Add()ed.
	// If you must use SDL before calling Run(), call StartSDL() first.
	bool Run();

	// Quit the program.
	void Quit();


private:
	class ViewData {
	public:
		View *view;
		Surface surface;
		// Store the bounds separately so that they can be initialized before the surface,
		// and so that the bounds can have negative values (for relative positioning).
		Rectangle rawBounds;
		Rectangle bounds;
		// This stores whether the view is visible.
		bool isVisible;
		// Stores whether we've run Initialize() on this view.
		bool isInitialized;

		// These functors are called when the view is removed.
		list<Callback *> callbacks;
	};


private:
	// Initialize SDL, create the window, and initialize all views.
	bool Initialize();
	// Redraw the window.
	void Draw();
	// Create a new view from the given view data.
	void CreateView(ViewData &viewData);


private:
	// Dimensions of the view. These should not be used after Initialize().
	int width;
	int height;
	// Additional display flags.
	Uint32 flags;

	// This stores whether the view positions are locked.
	bool canDragViews;

	// Store the views in a list so that we can easily move one to the top without
	// having to copy the ViewData objects.
	list<ViewData> views;

	// The background of the Interface should be filled with this color.
	int red;
	int green;
	int blue;
	bool showBackground;
};



#endif



/* Copyright (c) 2008 Michael Zahniser

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. */
